import axios from "axios";
import type {
  AxiosRequestConfig,
  AxiosError,
  AxiosResponse,
  InternalAxiosRequestConfig,
} from "axios";
import userService from "../utils/userService";
import TokenManager from "../utils/TokenManager";
import { ResponseCode } from "../enum/http";
import alertService from "../utils/alertService";

// 声明一个全局事件发布器，用于通知应用其他部分打开登录窗口
export const requestEvents = {
  // 保存回调函数的对象
  listeners: {
    openLogin: [] as Array<() => void>,
  },

  // 触发事件
  emit(event: "openLogin") {
    this.listeners[event].forEach((callback) => callback());
  },

  // 注册事件监听
  on(event: "openLogin", callback: () => void) {
    this.listeners[event].push(callback);
    // 返回取消订阅的函数
    return () => {
      this.listeners[event] = this.listeners[event].filter(
        (cb) => cb !== callback
      );
    };
  },
};

// 扩展AxiosRequestConfig类型以支持metadata字段
interface ExtendedAxiosRequestConfig extends InternalAxiosRequestConfig {
  metadata?: {
    startTime: number;
  };
}

// 自定义配置接口，用于标记重试状态
interface CustomAxiosConfig extends AxiosRequestConfig {
  _retry?: boolean; // 用于标记是否正在重试
}

/**
 * 标准API响应接口
 * @template T 响应数据类型
 */
export interface ApiResponse<T = unknown> {
  /** 状态码 */
  code: number;
  /** 响应数据 */
  data: T;
  /** 响应消息 */
  message: string;
}

// 创建Axios实例
const api = axios.create({
  // 使用代理路径替换远程URL
  baseURL: "https://www.beloved.ltd:8089",
  withCredentials: true,
});

/**
 * 标准化响应数据格式
 * @param response Axios响应对象
 * @returns 标准化的API响应
 */
const standardizeResponse = <T>(response: AxiosResponse): ApiResponse<T> => {
  // 如果后端已经返回标准格式，直接返回
  if (
    response.data &&
    typeof response.data === "object" &&
    "code" in response.data &&
    "data" in response.data &&
    "message" in response.data
  ) {
    return response.data as ApiResponse<T>;
  }

  // 后端未返回标准格式，进行封装
  return {
    code: response.status,
    data: response.data as T,
    message: "请求成功",
  };
};

/**
 * 标准化错误响应格式
 * @param error Axios错误或普通错误
 * @returns 标准化的API响应
 */
const standardizeError = <T>(error: AxiosError | Error): ApiResponse<T> => {
  if (axios.isAxiosError(error)) {
    // 处理网络错误或服务器返回的错误
    const { response, message } = error;

    console.error("请求错误:", error);

    if (response) {
      // 服务器返回了错误响应
      return {
        code: response.status,
        message: response.statusText || "请求失败",
        data: response.data as T,
      };
    }

    // 网络错误或请求被取消
    return {
      code: 500,
      message: message || "网络错误",
      data: null as unknown as T,
    };
  }

  // 非 Axios 错误
  return {
    code: 500,
    message: (error as Error).message || "未知错误",
    data: null as unknown as T,
  };
};

// 请求拦截器 - 添加Authorization头
api.interceptors.request.use(
  async (config: InternalAxiosRequestConfig) => {
    // 添加请求时间戳
    const extendedConfig = config as ExtendedAxiosRequestConfig;
    extendedConfig.metadata = { startTime: Date.now() };
    const user_fingerprint = localStorage.getItem("user_fingerprint");
    if (user_fingerprint) {
      config.headers.set("X-Device-Id", user_fingerprint);
    }
    // 从 TokenManager 获取 token
    const token = TokenManager.getToken();
    if (token) {
      if (config.headers && typeof config.headers.set === "function") {
        config.headers.set("Authorization", token);
      } else {
        config.headers.Authorization = token;
      }
    }

    return config;
  },
  (error: AxiosError) => {
    return Promise.reject(error);
  }
);

// 响应拦截器 - 处理token刷新和授权
api.interceptors.response.use(
  async (response: AxiosResponse) => {
    // 记录响应时间
    const config = response.config as ExtendedAxiosRequestConfig;
    if (config.metadata) {
      const endTime = Date.now();
      const duration = endTime - config.metadata.startTime;

      // 标记慢请求
      if (duration > 1000) {
        console.warn(`慢请求警告: ${config.url} 请求耗时 ${duration}ms`);
      }
    }
    const { data, config: reqConfig, headers } = response;

    // 1. 检查响应头中是否有token并更新
    const authorization = headers["authorization"] || headers["Authorization"];
    if (authorization && typeof authorization === "string") {
      TokenManager.setToken(authorization);
    }

    // 2. 处理token过期/无效的情况
    if (
      data.code === ResponseCode.TOKEN_EXPIRED ||
      data.code === ResponseCode.NOT_TOKEN_ERROR ||
      data.code === ResponseCode.NO_AUTH_ERROR
    ) {
      const originalRequest = reqConfig as CustomAxiosConfig;

      // 防止重试循环
      if (!originalRequest._retry) {
        originalRequest._retry = true;

        try {
          // 尝试刷新token
          alertService.info("Token失效,尝试刷新...");
          const refreshResponse = await refreshToken();

          // 获取新token
          const newToken =
            refreshResponse.headers["authorization"] ||
            refreshResponse.headers["Authorization"];

          if (newToken) {
            // 更新token并重试原始请求
            TokenManager.setToken(newToken);

            // 确保请求头存在
            if (!originalRequest.headers) {
              originalRequest.headers = {};
            }

            originalRequest.headers.Authorization = newToken;

            // 重新发送原始请求
            return api(originalRequest);
          }
        } catch (error) {
          alertService.error("刷新token失败");
          return Promise.reject(error);
        }
      }
    }

    // 3. 处理refreshToken也失效的情况
    if (
      data.code === ResponseCode.NOT_LOGIN_ERROR ||
      data.code === ResponseCode.REFRESH_TOKEN_EXPIRED
    ) {
      // 检查是否是用户主动登出请求，如果是，则不显示额外的提示
      const isLogoutRequest =
        reqConfig.url && reqConfig.url.includes("/user/login/logout");

      if (!isLogoutRequest) {
        alertService.error("RefreshToken失效,需要重新登录");
      }

      // 清除用户状态
      userService.logout();

      // 通知应用打开登录模态框
      requestEvents.emit("openLogin");

      // 返回错误以便上层组件处理
      return Promise.reject(new Error("登录已过期，请重新登录"));
    }
    if (data.code === ResponseCode.FORBIDDEN_ERROR) {
      alertService.warning("请先登录后再操作");
      requestEvents.emit("openLogin");
      return Promise.reject(new Error("未授权访问"));
    }
    // 4. 正常返回响应
    return response;
  },
  async (error: AxiosError) => {
    // 统一处理网络错误等非业务异常
    console.error("请求发生错误:", error);
    console.log(error.response?.status, "错误");
    return Promise.reject(error);
  }
);

/**
 * 批量并行处理多个API请求
 * @template T 响应数据类型的元组类型
 * @param requests 请求函数数组，每个函数返回一个Promise
 * @returns Promise<T> 各个请求响应的数组
 */
export const batchRequest = async <T extends unknown[]>(
  requests: Array<() => Promise<T[number]>>
): Promise<T> => {
  try {
    // 并行执行所有请求
    const results = await Promise.all(requests.map((request) => request()));
    return results as T;
  } catch (error) {
    // 捕获并统一处理错误
    console.error("批量请求错误:", error);
    throw error;
  }
};

/**
 * 发送GET请求
 * @template T 响应数据类型
 * @param url 请求路径
 * @param config 请求配置
 * @returns Promise<ApiResponse<T>>
 */
export const get = async <T = unknown>(
  url: string,
  config?: AxiosRequestConfig
): Promise<ApiResponse<T>> => {
  try {
    const response = await api.get(url, config);
    return standardizeResponse<T>(response);
  } catch (error) {
    return standardizeError<T>(error as Error);
  }
};

/**
 * 发送POST请求
 * @template T 响应数据类型
 * @template D 请求数据类型
 * @param url 请求路径
 * @param data 请求数据
 * @param config 请求配置
 * @returns Promise<ApiResponse<T>>
 */
export const post = async <T = unknown, D = unknown>(
  url: string,
  data?: D,
  config?: AxiosRequestConfig
): Promise<ApiResponse<T>> => {
  try {
    const response = await api.post(url, data, config);
    return standardizeResponse<T>(response);
  } catch (error) {
    return standardizeError<T>(error as Error);
  }
};

/**
 * 发送PUT请求
 * @template T 响应数据类型
 * @template D 请求数据类型
 * @param url 请求路径
 * @param data 请求数据
 * @param config 请求配置
 * @returns Promise<ApiResponse<T>>
 */
export const put = async <T = unknown, D = unknown>(
  url: string,
  data?: D,
  config?: AxiosRequestConfig
): Promise<ApiResponse<T>> => {
  try {
    const response = await api.put(url, data, config);
    return standardizeResponse<T>(response);
  } catch (error) {
    return standardizeError<T>(error as Error);
  }
};

/**
 * 发送DELETE请求
 * @template T 响应数据类型
 * @param url 请求路径
 * @param config 请求配置
 * @returns Promise<ApiResponse<T>>
 */
export const del = async <T = unknown>(
  url: string,
  config?: AxiosRequestConfig
): Promise<ApiResponse<T>> => {
  try {
    const response = await api.delete(url, config);
    return standardizeResponse<T>(response);
  } catch (error) {
    return standardizeError<T>(error as Error);
  }
};

/**
 * 刷新token函数
 * 使用refreshToken获取新的访问token
 * @returns Promise<AxiosResponse>
 */
export const refreshToken = async (): Promise<AxiosResponse> => {
  const refreshToken = TokenManager.getRefreshToken();
  if (!refreshToken) {
    throw new Error("没有刷新令牌");
  }

  return api.get("/user/login/auth/refresh_token", {
    headers: {
      Cookie: `refresh_token=${refreshToken}`,
    },
  });
};

// 导出默认对象
const request = {
  get,
  post,
  put,
  delete: del,
  batchRequest,
  api, // 导出API实例供直接使用
};

export default request;
